package com.example.administrator.myapplication.net;

import android.text.TextUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

public class HttpCodec {
    //回车和换行
    static final String CRLF = "\r\n";
    static final int CR = 13;
    static final int LF = 10;
    static final String SPACE = " ";
    static final String VERSION = "HTTP/1.1";
    static final String COLON = ":";


    public static final String HEAD_HOST = "Host";
    public static final String HEAD_CONNECTION = "Connection";
    public static final String HEAD_CONTENT_TYPE = "Content-Type";
    public static final String HEAD_CONTENT_LENGTH = "Content-Length";
    public static final String HEAD_TRANSFER_ENCODING = "Transfer-Encoding";

    public static final String HEAD_VALUE_KEEP_ALIVE = "Keep-Alive";
    public static final String HEAD_VALUE_CHUNKED = "chunked";

    ByteBuffer byteBuffer;

    public HttpCodec() {
        byteBuffer = ByteBuffer.allocate(10 * 1024);
    }

    public void writeRequest(OutputStream os, Request request) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append(request.method())
                .append(SPACE)
                .append(request.url().file)
                .append(SPACE)
                .append(VERSION)
                .append(CRLF);

        //请求头
        Map<String, String> headers = request.headers();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            sb.append(entry.getKey())
                    .append(COLON)
                    .append(SPACE)
                    .append(entry.getValue())
                    .append(CRLF);
        }

        sb.append(CRLF);

        //请求体
        RequestBody body = request.body();
        if (body != null) {
            sb.append(body.body());
        }

        os.write(sb.toString().getBytes());


    }

    public String readLine(InputStream is) throws Exception {
        byteBuffer.clear();
        byteBuffer.mark();
        byte b;
        boolean isMaybeEofline = false;
        while ((b = (byte) is.read()) != -1) {
            byteBuffer.put(b);
            if (b == CR) {
                isMaybeEofline = true;
            } else if (isMaybeEofline) {
                if (b == LF) {
                    byte[] lineBytes = new byte[byteBuffer.position()];
                    byteBuffer.reset();
                    byteBuffer.get(lineBytes);
                    return new String(lineBytes);
                }
            }

        }
        throw new IOException("Response line");
    }

    public HashMap<String, String> readHeaders(InputStream is) throws Exception {
        HashMap<String, String> headers = new HashMap<>();
        while (true) {
            String line = readLine(is);
            if (isEmptyLine(line)) {
                break;
            }
            int index = line.indexOf(":");
            if (index > 0) {
                String key = line.substring(0, index);
                String value = line.substring(index + 2, line.length() - 2);
                headers.put(key, value);
            }
        }

        return headers;

    }

    private boolean isEmptyLine(String line) {
        return TextUtils.equals(line, CRLF);
    }

    public byte[] readBytes(InputStream is, int len) throws Exception {
        byte[] bytes = new byte[len];
        int readNum = 0;
        while (true) {
            readNum += is.read(bytes, readNum, len - readNum);
            if (readNum == len) {
                return bytes;
            }
        }

    }

    public String readChunked(InputStream is) throws Exception {
        int len = -1;
        boolean isEmpty = false;
        StringBuffer sb = new StringBuffer();
        while (true) {
            if (len == -1) {
                String line = readLine(is);
                line = line.substring(0, line.length() - 2);
                len = Integer.valueOf(line, 16);
                isEmpty = len == 0;
            } else {
                byte[] bytes = readBytes(is, len + 2);
                sb.append(new String(bytes));
                len = -1;
                if (isEmpty){
                    return sb.toString();
                }
            }
        }
    }
}
